package vn.edu.hcmuns.selab.arm.ui.wizards;

import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.dialogs.WizardNewProjectCreationPage;

import vn.edu.hcmuns.selab.arm.core.builder.ARMProjectNature;
import vn.edu.hcmuns.selab.arm.ui.ARMPlugin;
import vn.edu.hcmuns.selab.arm.ui.utility.MessageUtil;
import vn.edu.hcmuns.selab.arm.ui.utility.ResourceUtil;

public class NewARMProjectWizard extends Wizard implements INewWizard {

    protected ISelection selection;
    protected WizardNewProjectCreationPage newARMProjectPage;
    
    public NewARMProjectWizard() {
        super();
        setNeedsProgressMonitor(true);
    }

    @Override
    public boolean performFinish() {
        try {
            getContainer().run(false, true, new WorkspaceModifyOperation() {
                protected void execute(IProgressMonitor monitor) {
                    createProject(monitor != null ? monitor
                            : new NullProgressMonitor());
                }
            });
        } catch (InvocationTargetException ex) {
            MessageUtil.reportError(ex.getMessage(), "Create project error", getShell());
            ex.printStackTrace();
            return false;
        } catch (InterruptedException ex) {
            MessageUtil.reportError(ex.getMessage(), "Create project error", getShell());
            ex.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    public void init(IWorkbench workbench, IStructuredSelection selection) {
        this.selection = selection;
    }

    @Override
    public void addPages() {
        newARMProjectPage = new WizardNewProjectCreationPage(
                "NewARMProjectWizard");
        newARMProjectPage.setTitle("Create a ARM project");
        newARMProjectPage
                .setDescription("Create a ARM project in the workspace or in an external location.");
        newARMProjectPage.setImageDescriptor(ImageDescriptor.createFromFile(
                getClass(), "/icons/wizban/newarmprj_wiz.gif"));
        addPage(newARMProjectPage);
    }

    protected void createProject(IProgressMonitor monitor) {

        String projectName = newARMProjectPage.getProjectName();
        monitor.beginTask("Creating project " + projectName + "...", 80);

        try {
            IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
            monitor.subTask("Creating directories ...");

            IProject project = (IProject) root.getProject(projectName);
            IProjectDescription description = ResourcesPlugin.getWorkspace()
                    .newProjectDescription(project.getName());

            if (!Platform.getLocation().equals(
                    newARMProjectPage.getLocationPath()))
                description.setLocation(newARMProjectPage.getLocationPath());

            project.create(description, monitor);

            monitor.worked(10);
            project.open(monitor);

            description = project.getDescription();
            description.setNatureIds(new String[] { ARMProjectNature.NATURE_ID });

            project.setDescription(description, new SubProgressMonitor(monitor,
                    10));

            IPath projectPath = project.getFullPath(), srcPath = projectPath
                    .append(ARMPlugin.DEFAULT_SOURCE_DIR), incPath = projectPath
                    .append(ARMPlugin.DEFAULT_INC_DIR), flashPath = projectPath
                    .append(ARMPlugin.DEFAULT_FLASH_DIR), resourcePath = projectPath
                    .append(ARMPlugin.DEFAULT_RESOURCE_DIR);

            IFolder srcFolder = root.getFolder(srcPath), incFolder = root
                    .getFolder(incPath), flashFolder = root
                    .getFolder(flashPath), resourceFolder = root
                    .getFolder(resourcePath);

            createFolderHelper(srcFolder, monitor);
            createFolderHelper(incFolder, monitor);
            createFolderHelper(flashFolder, monitor);
            createFolderHelper(resourceFolder, monitor);

            monitor.worked(10);
            monitor.subTask("Creating files...");

            IPath mainPath = srcPath.append("main.c"), lpc23xxPath = srcPath
                    .append("LPC23xx.h"), lpc2300Path = srcPath
                    .append("LPC2300.s"), makefilePath = projectPath
                    .append("Makefile"), targetPath = projectPath
                    .append("target.ld");

            IFile mainFile = root.getFile(mainPath), lpc23xxFile = root
                    .getFile(lpc23xxPath), lpc2300File = root
                    .getFile(lpc2300Path), makefile = root
                    .getFile(makefilePath), targetFile = root
                    .getFile(targetPath);

            InputStream mainIS = ResourceUtil.getResource("templates/main.c"),
                        lpc23xxIS = ResourceUtil.getResource("templates/LPC23xx.h"),
                        lpc2300IS = ResourceUtil.getResource("templates/LPC2300.s"),
                        targetIS = ResourceUtil.getResource("templates/target.ld"),
                        makefileIS = ResourceUtil.getResource("templates/Makefile");
                        
            mainFile.create(mainIS, false, new SubProgressMonitor(monitor, 10));
            lpc23xxFile.create(lpc23xxIS, false, new SubProgressMonitor(
                    monitor, 10));
            lpc2300File.create(lpc2300IS, false, new SubProgressMonitor(
                    monitor, 10));
            makefile.create(makefileIS, false, new SubProgressMonitor(monitor,
                    10));
            targetFile.create(targetIS, false, new SubProgressMonitor(monitor,
                    10));

        } catch (CoreException ex) {
            MessageUtil.reportError(ex.getMessage(), "Create project error", getShell());
            ex.printStackTrace();
        } finally {
            monitor.done();
        }
    }

    /**
     * Helper method: it recursively creates a folder path.
     * 
     * @param folder
     * @param monitor
     * @throws CoreException
     * @see java.io.File#mkdirs()
     */
    private void createFolderHelper(IFolder folder, IProgressMonitor monitor)
            throws CoreException {
        if (!folder.exists()) {
            IContainer parent = folder.getParent();
            if (parent instanceof IFolder && (!((IFolder) parent).exists()))
                createFolderHelper((IFolder) parent, monitor);
            folder.create(false, true, monitor);
        }
    }
}
